using System.Drawing;
using System.Drawing.Imaging;


namespace CommonLibraries.ProjectCommon.Helpers
{
    /// <summary>
    /// Defines members that assist in image manipulation operations.
    /// </summary>
    public static class ImageHelper
    {                
        /// <summary>
        /// Changes the dimensions of a <see cref="System.Drawing.Bitmap"/> object given a new desired size.
        /// </summary>
        /// 
        /// <exception cref="System.ArgumentNullException">Thrown if the passed-in <see cref="System.Drawing.Bitmap"/> object
        /// is <c>null</c>.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the new pixel values are negative or zero. Thrown using 
        /// <see cref="ExceptionHelper.Throw(System.Exception)"/>, which controls logging and other exception handling activities.</exception>
        /// 
        /// <param name="originalBitmap">The <see cref="System.Drawing.Bitmap"/> object to modify.</param>
        /// <param name="desiredHeight">The new height in pixels, which must be 1 or more.</param>
        /// <param name="desiredWidth">The new width in pixels, which must be 1 or more.</param>
        /// <returns>A resized <see cref="System.Drawing.Bitmap"/> object.</returns>
        /// <remarks>Creates a standard <see cref="System.Drawing.Graphics"/> object to alter and draw the given <see cref="System.Drawing.Bitmap"/> 
        /// object using <see cref="System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic"/> interpolation mode.
        /// The <see cref="System.Drawing.Graphics"/> object is <see cref="System.Drawing.Graphics.Dispose"/>ed of before exiting.
        /// </remarks>
        public static Bitmap ResizeWithExact(System.Drawing.Image originalBitmap, int desiredWidth, int desiredHeight)
        {
            if (originalBitmap == null)
            {
                //ExceptionHelper.Throw(new System.ArgumentNullException("originalBitmap"));
                return null;
            }
            if (desiredWidth < 1)
            {
                //ExceptionHelper.Throw(new System.ArgumentOutOfRangeException("desiredWidth", "ResizeWithExact: Pixel count must be 1 or more."));
                return null;
            }
            if (desiredHeight < 1)
            {
                //ExceptionHelper.Throw(new System.ArgumentOutOfRangeException("desiredHeight", "ResizeWithExact: Pixel count must be 1 or more."));
                return null;
            }
            Bitmap _NewBitmap;
            _NewBitmap = new Bitmap(desiredWidth, desiredHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            Graphics _Surface;
            _Surface = Graphics.FromImage(_NewBitmap);
            //_Surface.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            //_Surface.DrawImage(originalBitmap, 0, 0, desiredWidth, desiredHeight);
            _Surface.Dispose();
            return _NewBitmap;
        }

        /// <summary>
        /// Proportionately changes the size of a <see cref="System.Drawing.Bitmap"/> object given the new desired height.
        /// </summary>
        /// <exception cref="System.ArgumentNullException">Thrown if the passed-in <see cref="System.Drawing.Bitmap"/> object
        /// is <c>null</c>.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the new pixel value is negative or zero. Thrown using 
        /// <see cref="ExceptionHelper.Throw(System.Exception)"/>, which controls logging and other exception handling activities.</exception>
        /// 
        /// <param name="originalBitmap">The <see cref="System.Drawing.Bitmap"/> object to modify.</param>
        /// <param name="desiredHeight">The new height in pixels.</param>
        /// 
        /// <returns>A resized <see cref="System.Drawing.Bitmap"/> object.</returns>
        /// 
        /// <remarks><para>Calculates a rate of change from the value of <paramref name="desiredHeight"/> and the height of the
        /// <paramref name="originalBitmap"/>, which is then used to find out the proportional change in width. The new width value is then sent 
        /// to the <see cref="ProjectCommon.Helpers.ImageHelper.ResizeWithExact(System.Drawing.Image, int, int)"/> method along with the other parameters given
        /// to this method.</para>
        /// <para>Note that since these calculations are performed using fractional numbers, the <see cref="System.Convert.ToInt32(double)"/> method is used to 
        /// convert the calculated width back into an integer that can be used as a pixel measurement. Thus, the final change in width may not be exactly 
        /// proportional to the change in height. See the documentation for the <c>ToInt32()</c> method for information on how the rounding is performed.</para>
        /// </remarks>
        public static Bitmap ResizeWithAspectByHeight(System.Drawing.Image originalBitmap, int desiredHeight)
        {
            if (originalBitmap == null)
            {
                //Helpers.ExceptionHelper.Throw(new System.ArgumentNullException("originalBitmap"));
                return null;
            }
            if (desiredHeight < 1)
            {
                //ExceptionHelper.Throw(new System.ArgumentOutOfRangeException("desiredHeight", "ResizeWithExact: Pixel count must be 1 or more."));
                return null;
            }

            double _Multiplier;
            _Multiplier = (double)desiredHeight / (double)originalBitmap.Height;

            int _DerivedWidth;
            _DerivedWidth = System.Convert.ToInt32((double) originalBitmap.Width * _Multiplier);

            return ResizeWithExact(originalBitmap, _DerivedWidth, desiredHeight);
        }

        /// <summary>
        /// Proportionately changes the size of a <see cref="System.Drawing.Bitmap"/> object given the new desired width.
        /// </summary>
        /// <exception cref="System.ArgumentNullException">Thrown if the passed-in <see cref="System.Drawing.Bitmap"/> object
        /// is <c>null</c>.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the new pixel value is negative or zero. Thrown using 
        /// <see cref="ExceptionHelper.Throw(System.Exception)"/>, which controls logging and other exception handling activities.</exception>
        /// 
        /// <param name="originalBitmap">The <see cref="System.Drawing.Bitmap"/> object to modify.</param>
        /// <param name="desiredWidth">The new width in pixels.</param>
        /// 
        /// <returns>A resized <see cref="System.Drawing.Bitmap"/> object.</returns>
        /// 
        /// <remarks><para>Calculates a rate of change from the value of <paramref name="desiredWidth"/> and the width of the
        /// <paramref name="originalBitmap"/>, which is then used to find out the proportional change in height. The new height value is then sent 
        /// to the <see cref="ProjectCommon.Helpers.ImageHelper.ResizeWithExact(System.Drawing.Image, int, int)"/> method along with the other parameters given
        /// to this method.</para>
        /// <para>Note that since these calculations are performed using fractional numbers, the <see cref="System.Convert.ToInt32(double)"/> method is used to 
        /// convert the calculated height back into an integer that can be used as a pixel measurement. Thus, the final change in height may not be exactly 
        /// proportional to the change in width. See the documentation for the <c>ToInt32()</c> method for information on how the rounding is performed.</para>
        /// </remarks>
        public static Bitmap ResizeWithAspectByWidth(System.Drawing.Image originalBitmap, int desiredWidth)
        {
            if (originalBitmap == null)
            {
                //Helpers.ExceptionHelper.Throw(new System.ArgumentNullException("originalBitmap"));
                return null;
            }
            if (desiredWidth < 1)
            {
                //ExceptionHelper.Throw(new System.ArgumentOutOfRangeException("desiredWidth", "ResizeWithExact: Pixel count must be 1 or more."));
                return null;
            }

            double Multiplier;
            Multiplier = (double)desiredWidth / (double)originalBitmap.Width;

            int DerivedHeight;
            DerivedHeight = System.Convert.ToInt32((double)originalBitmap.Height * Multiplier);

            return ResizeWithExact(originalBitmap, desiredWidth, DerivedHeight);
        }

        /// <summary>
        /// Convert ushortType into an image and save this width the universaltime.jpeg
        /// </summary>
        /// <param name="bushort"></param>
        /// <returns></returns>
        public static Bitmap ushortToImage(byte[] bushort)
        {
            System.IO.MemoryStream ms = new System.IO.MemoryStream(bushort);
            System.Drawing.Bitmap b = new Bitmap(ms);
            b.Save(System.DateTime.Now.ToString(), System.Drawing.Imaging.ImageFormat.Jpeg);
            return b;
        }

    
    }

    /// <summary>
    /// Represents a two-dimensional bitmap image and exposes members that allow it to be manipulated.
    /// </summary>
//    public class CustomImage
//    {
//        #region " Constructors and destructor "

//        /// <summary>
//        /// Creates a new, empty instance of <c>CustomImage</c>.
//        /// </summary>
//        public CustomImage()
//        {
//        }

//        /// <summary>
//        /// Creates a new instance of <c>CustomImage</c> from the given file.
//        /// </summary>
//        /// <param name="filePath">The path and file name of the file that contains a bitmap image.</param>
//        /// <remarks>Simply calls the object's <see cref="Open(string)"/> method, passing along the given string. Note that this call could
//        /// generate an exception if the given path is invalid.</remarks>
//        public CustomImage(string filePath)
//        {
//            Open(filePath);
//        }

//        /// <summary>
//        /// Destroys the current intance of <c>CustomImage</c>.
//        /// </summary>
//        ~CustomImage()
//        {
//            if (BaseBitmap != null)
//            {
//                BaseBitmap.Dispose();
//            }
//        }

//        #endregion

//        #region " Enumerations "

//        /// <summary>
//        /// Defines a list of constants whose values determine the method to use when saving an image.
//        /// </summary>
//        public enum SaveMethod
//        {
//            /// <summary>
//            /// Specifies that a file should be saved to disk with the exact name specified, but if a file with the same name already exists, 
//            /// the operation should be aborted to avoid overwriting the existing file.
//            /// </summary>
//            Normal,

//            /// <summary>
//            /// Specifies that a file should be saved to disk with the exact name specified; if a file with the same name already exists, it should be
//            /// replaced by the new file.
//            /// </summary>
//            Overwrite,

//            /// <summary>
//            /// Specifies that a file should be saved to disk after modifying its name so that it does not conflict with an existing file's name.
//            /// </summary>
//            Increment
//        }

//        /// <summary>
//        /// Defines a list of constants that represent the dimensions of an image.
//        /// </summary>
//        public enum ImageDimension
//        {
//            /// <summary>
//            /// Represents the space between the sides of an image.
//            /// </summary>
//            Width,

//            /// <summary>
//            /// Represents the space between the top and bottom of an image.
//            /// </summary>
//            Height
//        }

//        #endregion

//        #region " Properties "

//        /// <summary>
//        /// Stores a bitmap image.
//        /// </summary>
//        private Bitmap _BaseBitmap;

//        /// <summary>
//        /// Gets or Sets the actual image represented by the current instance of <c>CustomImage</c>.
//        /// </summary>
//        /// <value>A <see cref="System.Drawing.Bitmap"/> object or <c>null</c> if there is no image currently stored in the object.</value>
//        public Bitmap BaseBitmap
//        {
//            get
//            {
//                return _BaseBitmap;
//            }
//            set
//            {
//                _BaseBitmap = value;
//            }
//        }

//        #endregion

//        #region " Methods "

//        /// <summary>
//        /// Loads a new bitmap image from the given file.
//        /// </summary>
//        /// <exception cref="System.ArgumentException">Thrown if the given path is <c>null</c> or empty. Thrown using 
//        /// <see cref="ProjectCommon.Helpers.ExceptionHelper.Throw(System.Exception)"/>, with the message "CustomImage.Open: The given file path is null or empty.".</exception>
//        /// <param name="filePath">The path and name of the file to load.</param>
//        /// <remarks>Simply creates a new <c>Bitmap</c> object using the <see cref="Bitmap(string)"/> constructor.</remarks>
//        public void Open(string filePath)
//        {
//            if (string.IsNullOrEmpty(filePath))
//            {
//                ExceptionHelper.Throw(new System.ArgumentNullException("filePath", "CustomImage.Open: The given file path is null or empty."));
//                return;
//            }
//            try
//            {
//                BaseBitmap = new Bitmap(filePath);
//            }
//            catch (System.ArgumentException _ArgEx)
//            {
//                ExceptionHelper.Throw(_ArgEx);
//                return;
//            }
//        }

//        /// <summary>
//        /// Changes the current image's dimensions to the given new sizes.
//        /// </summary>
//        /// <exception cref="System.InvalidOperationException">Thrown if this method is called when there is no image to resize in the current instance of 
//        /// <c>CustomImage</c>. Thrown using <see cref="ExceptionHelper.Throw(System.Exception)"/>, which controls logging and other exception handling activities.</exception>
//        /// <param name="desiredHeight">The new height in pixels.</param>
//        /// <param name="desiredWidth">The new width in pixels.</param>
//        /// <remarks>This method simply calls the <see cref="ImageHelper.ResizeWithExact"/> method, specifying the current image stored in this object as
//        /// the bitmap to resize.</remarks>
//        public void Resize(int desiredWidth, int desiredHeight)
//        {
//            if (BaseBitmap == null)
//            {
//                ExceptionHelper.Throw(new System.InvalidOperationException("CustomImage.Resize: No bitmap loaded yet."));
//                return;
//            }
            
//            BaseBitmap = ImageHelper.ResizeWithExact(BaseBitmap, desiredWidth, desiredHeight);
//        }

//        /// <summary>
//        /// Changes the specified dimension of the current image to the given size. Provides the option to preserve the image's aspect ratio.
//        /// </summary>
//        /// <exception cref="System.InvalidOperationException">Thrown if this method is called when there is no image to resize in the current instance of 
//        /// <c>CustomImage</c>. Thrown using <see cref="ExceptionHelper.Throw(System.Exception)"/>, which controls logging and other exception handling activities.</exception>
//        /// 
//        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the new pixel value is negative or zero. Thrown using 
//        /// <see cref="ExceptionHelper.Throw(System.Exception)"/>, which controls logging and other exception handling activities.</exception>
//        /// 
//        /// <exception cref="System.ArgumentException">Thrown if the specified dimension to resize is other than <see cref="CustomImage.ImageDimension.Width"/> 
//        /// or <see cref="CustomImage.ImageDimension.Height"/>. Thrown using <see cref="ExceptionHelper.Throw(System.Exception)"/>, which controls logging and other 
//        /// exception handling activities.</exception>
//        /// 
//        /// <param name="dimensionToResize">The dimension to resize, which must be of type <see cref="CustomImage.ImageDimension"/>.</param>
//        /// <param name="desiredSize">The new size of the specified dimension, in pixels.</param>
//        /// <param name="preserveAspect">The value that determines if the dimension that was not specified will be automatically resized to conserve the 
//        /// image's aspect ratio, or if it will be left unmodified. Use <c>true</c> to conserve the image's proportions; <c>false</c> otherwise.</param>
//        /// 
//        /// <remarks><para>This method calls the <see cref="ImageHelper.ResizeWithExact"/> method if <paramref name="preserveAspect"/> is <c>false</c>. If it is 
//        /// <c>true</c>, it will call either the <see cref="ImageHelper.ResizeWithAspectByHeight"/> or the <see cref="ImageHelper.ResizeWithAspectByWidth"/>
//        /// method, depending on which dimension was specified to be changed in the <paramref name="dimensionToResize"/> parameter.</para>
//        /// <para>Note that the last two methods perform calculations using fractional numbers, and round the final number back to an integer, so the final change 
//        /// in the dimension that was not specified may not be exactly proportional to the change in the one that was specified. See the documentation for those 
//        /// methods for more information on how the rounding is performed.</para>
//        /// </remarks>
//        public void Resize(ImageDimension dimensionToResize, int desiredSize, bool preserveAspect)
//        {
//            if (BaseBitmap == null)
//            {
//                ExceptionHelper.Throw(new System.InvalidOperationException("CustomImage.Resize: No bitmap loaded yet."));
//                return;
//            }
//            if (desiredSize < 1)
//            {
//                ExceptionHelper.Throw(new System.ArgumentOutOfRangeException("desiredSize", "CustomImage.Resize: Pixel count must be 1 or more."));
//                return;
//            }
//            if (dimensionToResize == ImageDimension.Width || dimensionToResize == ImageDimension.Height)
//            {
//                // Determine which Resize method to call
//                if (preserveAspect == false)
//                {
//                    if (dimensionToResize == ImageDimension.Height)
//                    {
//                        BaseBitmap = ImageHelper.ResizeWithExact(BaseBitmap, BaseBitmap.Width, desiredSize);
//                    }
//                    else
//                    {
//                        BaseBitmap = ImageHelper.ResizeWithExact(BaseBitmap, desiredSize, BaseBitmap.Height);
//                    }
//                }
//                else
//                {
//                    if (dimensionToResize == ImageDimension.Height)
//                    {
//                        BaseBitmap = ImageHelper.ResizeWithAspectByHeight(BaseBitmap, desiredSize);
//                    }
//                    else
//                    {
//                        BaseBitmap = ImageHelper.ResizeWithAspectByWidth(BaseBitmap, desiredSize);
//                    }
//                }
//            }
//            else
//            {
//                ExceptionHelper.Throw(new System.ArgumentException("CustomImage.Resize: The argument is not a dimension that this method can resize.", "dimensionToResize"));
//                return;
//            }
//        }

//        /// <summary>
//        /// Stores the current image to the given location in the file system.
//        /// </summary>
//        /// 
//        /// <exception cref="System.InvalidOperationException">Thrown if this method is called when no image has been loaded for the current instance of
//        /// <c>CustomImage</c>. Thrown using <see cref="ExceptionHelper.Throw(System.Exception)"/>, which controls logging and other exception handling activities.</exception>
//        /// 
//        /// <exception cref="System.ArgumentNullException">Thrown if the path to save to is null or empty, or if the image format parameter is null. Thrown using 
//        /// <see cref="ExceptionHelper.Throw(System.Exception)"/>, which controls logging and other exception handling activities.</exception>
//        /// 
//        /// <exception cref="System.ArgumentException">Thrown if the given file name is not valid. Thrown using <see cref="ExceptionHelper.Throw(System.Exception)"/>, 
//        /// which controls logging and other exception handling activities.</exception>
//        /// 
//        /// <exception cref="Exceptions.OutPathAlreadyExistsException">Thrown if <see cref="SaveMethod.Normal"/> was specified as the save method to use and 
//        /// the given file already exists. Thrown using <see cref="ExceptionHelper.Throw(System.Exception)"/>, which controls logging and other exception handling activities.
//        /// </exception>
//        /// 
//        /// <exception cref="System.NotImplementedException">Thrown if the specified <see cref="CustomImage.SaveMethod"/> is other than <c>Normal</c>, 
//        /// <c>Increment</c>, or <c>Overwrite</c>. Thrown using <see cref="ExceptionHelper.Throw(System.Exception)"/>, which controls logging and other exception handling 
//        /// activities.</exception>
//        /// 
//        /// <param name="filePath">The path and name of the file where the image will be stored. This method does not support the creation of directories if they
//        /// do not already exist.</param>
//        /// <param name="imageFormat">The format to save the image as.</param>
//        /// <param name="saveMethod">The method to use when saving the image, must be of type <see cref="SaveMethod"/>.
//        /// </param>
//        /// <returns>The path and name under which the file was saved.</returns>
//        /// 
//        /// <remarks><para>The method performs basic validity tests on the given path before attempting to save and throws exceptions as specified in 
//        /// the Exceptions section. However, exceptions thrown inside called methods are not listed here, although they are logged and rethrown using 
//        /// the <see cref="ExceptionHelper.Throw(System.Exception, ExceptionHelper.ThrowAction)"/> method.</para>
//        /// <para>The method then decides what to do depending on the value specified in the <paramref name="saveMethod"/> parameter. If:
//        /// <list type="bullet">
//        /// <item><c>SaveMethod.Increment</c> is specified, the <see cref="FileHelper.IncrementFileName(string)"/> method is called, sending
//        /// along the entire path given to this method. Using the returned path, the <see cref="Image.Save(string)"/> method is then called
//        /// to actually store the file.
//        /// </item>
//        /// <item><c>SaveMethod.Normal</c> is specified, the <see cref="System.IO.File.Exists(string)"/> method is called to check if the file
//        /// already exists. If it does, an <c>OutPathAlreadyExistsException</c> is thrown as specified in the "Exceptions" section. If it
//        /// does not, the method simply proceeds to call the <see cref="Image.Save(string)"/> method.
//        /// </item>
//        /// <item>SaveMethod.Overwrite is specified, the <see cref="System.IO.File.Exists(string)"/> method is called to check if the file
//        /// already exists. If it does, the method attempts to delete the existing file by calling the 
//        /// <see cref="ProjectCommon.Helpers.FileHelper.DeleteFile(string)"/> method. If it does not, the method simply proceeds to call the 
//        /// <see cref="Image.Save(string)"/> method.
//        /// </item>
//        /// </list></para>
//        /// <para>Note that the call to <see cref="Image.Save(string)"/> could generate exceptions that are not listed here, although they are
//        /// logged and rethrown using the <see cref="ExceptionHelper.Throw(System.Exception, ExceptionHelper.ThrowAction)"/> method.</para>
//        /// </remarks>
//        public string Save(string filePath, System.Drawing.Imaging.ImageFormat imageFormat, SaveMethod saveMethod)
//        {
//            if (BaseBitmap == null)
//            {
//                System.InvalidOperationException _Ex = new System.InvalidOperationException("CustomImage.Save: No image loaded yet.");
//                ExceptionHelper.Throw(_Ex, ExceptionHelper.ThrowAction.Throw);
//                return null;
//            }
//            if (string.IsNullOrEmpty(filePath))
//            {
//                System.ArgumentNullException _Ex = new System.ArgumentNullException("filePath", "CustomImage.Save: No file path was provided.");
//                ExceptionHelper.Throw(_Ex, ExceptionHelper.ThrowAction.Throw);
//                return null;
//            }
//            if (imageFormat == null)
//            {
//                ExceptionHelper.Throw(new System.ArgumentNullException("imageFormat"), ExceptionHelper.ThrowAction.Throw);
//                return null;
//            }
//            // Get filename to check it before calling Bitmap.Save, since it saves invalid names sometimes...
//            string _Filename;
//            try
//            {
//                _Filename = System.IO.Path.GetFileName(filePath);
//            }
//            catch (System.Exception _Ex)
//            {
//                ExceptionHelper.Throw(_Ex, ExceptionHelper.ThrowAction.Throw);
//                throw;
//            }
//            if (FileHelper.IsValidFilename(_Filename) == false) 
//            {
//                ExceptionHelper.Throw(new System.ArgumentException("The given file name is not a valid Windows file name.", "filePath"));
//                return null;
//            }

//            if (saveMethod == SaveMethod.Increment)
//            {
//                filePath = FileHelper.IncrementFileName(filePath);
//            }
//            else if (saveMethod == SaveMethod.Normal)
//            {
//                if (System.IO.File.Exists(filePath))
//                {
//                    ExceptionHelper.Throw(new ProjectCommon.Exceptions.OutPathAlreadyExistsException("CustomImage.Save: Cannot save since SaveMethod.Normal was specified."));
//                    return null;
//                }
//            }
//            else if (saveMethod == SaveMethod.Overwrite)
//            {
//                if (System.IO.File.Exists(filePath))
//                {
//                    ProjectCommon.Helpers.FileHelper.DeleteFile(filePath); //Can throw timeout if file is locked.
//                }
//            }
//            else
//            {
//                ExceptionHelper.Throw(new System.NotImplementedException("CustomImage.Save: The specified save method is not supported."));
//                return null;
//            }

//            try
//            {
//                BaseBitmap.Save(filePath, imageFormat);
//            }
//            catch (System.Exception _Ex)
//            {
//                ExceptionHelper.Throw(_Ex, ExceptionHelper.ThrowAction.Throw);
//                throw;
//            }
            
//            return filePath;
//        }

//        #endregion
//    }
}